/*

*/

#include <memory>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <functional>
#include <cstring>
#include "server.h"
#include "channel.h"
#include "eventloop.h"
#include "threadpool.h"
#include "httpData.h"
#include "util.h"

Server::Server(EventLoop *base,int port, int nums):m_started(false),m_base(base),m_port(port),m_listenfd(socket_bind_listen(port)),m_accept_channel(new Channel(base,m_listenfd)),m_threadpool(new ThreadPool(m_base,nums)),m_threadNums(nums){
    handler_for_sigpipe();
    if(setNonBlocking(m_listenfd)<0){
        record()<<"set m_listenfd failed";
        abort();//发送SIGABRT信号
    }
}

void Server::start(){
    m_threadpool->start();
    m_accept_channel->setEvents(EPOLLET|EPOLLIN);
    m_accept_channel->setReadHandler(std::bind(&Server::handleNewConn,this));
    m_accept_channel->setConnHandler(std::bind(&Server::handThisConn,this));
    m_base->add_event(m_accept_channel,0);
    m_started=true;
}

void Server::handleNewConn(){
    sockaddr_in client_addr;
    bzero(&client_addr,sizeof(client_addr));
    socklen_t client_addr_len=sizeof(client_addr);
    int acceptfd=0;
    while((acceptfd=accept(m_listenfd,(sockaddr*)&client_addr,&client_addr_len))>0){
        EventLoop *loop=m_threadpool->getNextLoop();
        record()<<"new connection from "<<inet_ntoa(client_addr.sin_addr)<<":"<<ntohs(client_addr.sin_port);
        // TCP的保活机制默认是关闭的,，可以通过下面几条语句开启
        /*
        int optval = 1;
        socklen_t len_optval = 4;
        setsockopt(accept_fd, SOL_SOCKET,  SO_KEEPALIVE, &optval, &len_optval);
        */
       if(acceptfd>=MAXFDS){
           close(acceptfd);
           continue;
       }
       if(setNonBlocking(acceptfd)<0){
           record()<<"set acceptfd nonblocking fail";
           perror("set acceptfd nonblocking fail");
           return;
       }
       setNodelay(acceptfd);
       std::shared_ptr<HttpData> req_info(new HttpData(loop,acceptfd));
       req_info->getChannel()->setHolder(req_info);
       loop->queueInloop(std::bind(&HttpData::newEvent,req_info));
    }
}

void Server::handThisConn(){
    
}